package com.xpxrule.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.xpxrule.constant.BusinessModelFieldValueType;
import com.xpxrule.dataobject.biz.model.ReturnResponse;
import com.xpxrule.dataobject.bo.FieldInfoBo;
import com.xpxrule.dataobject.dao.BusinessModel;
import com.xpxrule.dataobject.dao.EnumConstant;
import com.xpxrule.dataobject.dao.ModelItem;
import com.xpxrule.dataobject.req.BusinessModelQueryReq;
import com.xpxrule.dataobject.vo.BusinessModelVo;
import com.xpxrule.dataobject.vo.FieldInfoVo;
import com.xpxrule.dataobject.vo.OptionVo;
import com.xpxrule.ex.BusinessModelNotFindException;
import com.xpxrule.mapper.EnumConstantMapper;
import com.xpxrule.mapper.ModelItemMapper;
import com.xpxrule.util.FormatStringUtil;
import com.xpxrule.util.ModelConvertUtil;
import com.xpxrule.mapper.BusinessModelMapper;
import com.xpxrule.service.BusinessModelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @version 1.0
 * @Author xiangpengxiang
 * @Date 2024/11/20 19:28
 * @注释
 */
@Service
public class BusinessModelServiceImpl implements BusinessModelService {
    @Autowired
    private BusinessModelMapper businessModelMapper;
    @Autowired
    private ModelItemMapper modelItemMapper;
    @Autowired
    private EnumConstantMapper enumConstantMapper;

    @Override
    public ReturnResponse insert(BusinessModelVo vo) {
        boolean isExist = verifyDbUnique(vo.getModelKey());
        if (!isExist) {
            return ReturnResponse.fail("The unique verification failed. The new data already exists in the database.");
        }
        BusinessModel dao = ModelConvertUtil.convertBusinessModelVoToBusinessModel(vo);
        int count = businessModelMapper.insert(dao);
        return ReturnResponse.success(count);
    }

    @Transactional
    @Override
    public ReturnResponse delete(Long id) {
        // 存在性校验
        boolean isExist = verifyDbExistById(id);
        if (!isExist) {
            return ReturnResponse.fail("The data does not exist in the database.");
        }
        BusinessModel businessModel = businessModelMapper.selectById(id);
        businessModel.setIsDeleted(new Date());
        int count = businessModelMapper.updateById(businessModel);
        modelItemMapper.deleteModelItemByModelKey(businessModel.getModelKey());
        return ReturnResponse.success(count);
    }

    @Override
    public ReturnResponse update(BusinessModelVo vo) {
        boolean isExist = verifyDbExistById(Long.valueOf(vo.getId()));
        if (!isExist) {
            return ReturnResponse.fail("The data does not exist in the database.");
        }
        BusinessModel old = businessModelMapper.selectById(vo.getId());
        ModelConvertUtil.fillBusinessModelFromBusinessModelVo(old, vo);
        int count = businessModelMapper.updateById(old);
        return ReturnResponse.success(count);
    }

    @Override
    public ReturnResponse<List<BusinessModelVo>> selectList(BusinessModelQueryReq req) {
        List<BusinessModel> list = selectBusinessModelListByReq(req);
        List<BusinessModelVo> resultList = list.stream()
                .map(ModelConvertUtil::convertBusinessModelToBusinessModelVo)
                .collect(Collectors.toList());
        return new ReturnResponse<List<BusinessModelVo>>(resultList);
    }

    private List<BusinessModel> selectBusinessModelListByReq(BusinessModelQueryReq req) {
        QueryWrapper<BusinessModel> wrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(req.getModelName())) {
            wrapper.like(BusinessModel.COLUMN.MODEL_NAME, req.getModelName());
        }
        if (!StringUtils.isEmpty(req.getModelKey())) {
            wrapper.like(BusinessModel.COLUMN.MODEL_KEY, req.getModelKey());
        }
        if (!ObjectUtils.isEmpty(req.getIsEnable())) {
            wrapper.eq(BusinessModel.COLUMN.IS_ENABLE, req.getIsEnable());
        }
        wrapper.isNull(BusinessModel.COLUMN.IS_DELETED);
        return businessModelMapper.selectList(wrapper);
    }

    @Override
    public BusinessModel getBusinessModelByBusinessKey(String modelKey) {
        QueryWrapper<BusinessModel> wrapper = new QueryWrapper<>();
        wrapper.eq(BusinessModel.COLUMN.MODEL_KEY, modelKey);
        wrapper.isNull(BusinessModel.COLUMN.IS_DELETED);
        List<BusinessModel> list = businessModelMapper.selectList(wrapper);
        if (list.isEmpty()) {
            // todo 报错
        }
        return list.get(0);
    }

    @Override
    public ReturnResponse<List<OptionVo>> getAllBusinessModelOptions() {
        BusinessModelQueryReq req = new BusinessModelQueryReq();
        req.setIsEnable((short) 0);
        List<BusinessModel> list = selectBusinessModelListByReq(req);
        List<OptionVo> resultList = list.stream()
                .map(ModelConvertUtil::convertBusinessModelToOptionVo)
                .collect(Collectors.toList());
        return new ReturnResponse<>(resultList);
    }

    @Override
    public ReturnResponse<List<FieldInfoVo>> getFieldListByBusinessModelKey(String modelKey) {
        /**
         * 1：判断该业务模型是否合法
         * 2：获取业务模型下所有字段
         * 3：遍历所有字段逐级判断并获取
         */
        BusinessModel businessModel = getBusinessModelByModelKey(modelKey);
        if (businessModel == null) {
            ReturnResponse.fail("Business model not found");
        }
        List<FieldInfoBo> fieldList = new ArrayList<>();
        getBusinessModelFieldList(businessModel, fieldList, "", "");
        // 将字段转为vo
        List<FieldInfoVo> resultList = fieldList.stream()
                .map(ModelConvertUtil::convertFieldInfoBoToFieldInfoVo)
                .collect(Collectors.toList());
        return new ReturnResponse<>(resultList);
    }

    private void getBusinessModelFieldList(BusinessModel businessModel, List<FieldInfoBo> fieldList, String prefix, String zhPrefix) {
        List<ModelItem> modelItemList = getModelItemListByModelKey(businessModel.getModelKey());
        for (ModelItem modelItem : modelItemList) {
            BusinessModelFieldValueType fieldValueType = BusinessModelFieldValueType.getValueTypeByType(modelItem.getFieldValueType());
            switch (fieldValueType) {
                case BASIC_TYPE:
                    // 基础类型直接添加到结果中
                    FieldInfoBo basicFieldInfo = getFieldInfoBoByModelItem(prefix, zhPrefix, modelItem);
                    fieldList.add(basicFieldInfo);
                    break;
                case ENUM_CONSTANT:
                    // 枚举类型添加到结果集中
                    FieldInfoBo enumConstantFieldInfo = getFieldInfoBoByEnumConstantModelItem(prefix, zhPrefix, modelItem);
                    fieldList.add(enumConstantFieldInfo);
                    break;
                case CUSTOM_TYPE:
                    // 获取业务模型
                    getBusinessModelFieldList(
                            Objects.requireNonNull(getBusinessModelByModelKey(modelItem.getFieldType())),
                            fieldList,
                            FormatStringUtil.formatPrefix(prefix, modelItem.getFieldKey()),
                            FormatStringUtil.formatPrefix(zhPrefix, modelItem.getFieldName())
                    );
                    break;
                default:
                    break;
            }
        }
    }

    /**
     * 获取枚举字段信息
     * @param prefix
     * @param zhPrefix
     * @param modelItem
     * @return
     */
    private FieldInfoBo getFieldInfoBoByEnumConstantModelItem(String prefix, String zhPrefix, ModelItem modelItem) {
        FieldInfoBo fieldInfoBo = new FieldInfoBo();
        fieldInfoBo.setModelKey(modelItem.getModelKey());
        fieldInfoBo.setFieldName(modelItem.getFieldName());
        fieldInfoBo.setModelFieldName(FormatStringUtil.formatPrefix(prefix, modelItem.getFieldKey()));
        fieldInfoBo.setModelFieldZhName(FormatStringUtil.formatPrefix(zhPrefix, modelItem.getFieldName()));
        fieldInfoBo.setFieldValueType(modelItem.getFieldValueType());
        fieldInfoBo.setFieldType(modelItem.getFieldType());
        // 查询枚举信息补充基础类型
        EnumConstant enumConstant = getEnumConstantByConstantKey(modelItem.getFieldType());
        fieldInfoBo.setBasicFieldType(enumConstant.getItemType());
        return fieldInfoBo;
    }

    private EnumConstant getEnumConstantByConstantKey(String enumConstantKey) {
        QueryWrapper<EnumConstant> wrapper = new QueryWrapper<>();
        wrapper.eq(EnumConstant.COLUMN.CONSTANT_KEY, enumConstantKey);
        List<EnumConstant> list = enumConstantMapper.selectList(wrapper);
        if (list == null || list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    /**
     * 获取字段信息
     * @param prefix
     * @param zhPrefix
     * @param modelItem
     * @return
     */
    private FieldInfoBo getFieldInfoBoByModelItem(String prefix, String zhPrefix, ModelItem modelItem) {
        FieldInfoBo fieldInfoBo = new FieldInfoBo();
        fieldInfoBo.setModelKey(modelItem.getModelKey());
        fieldInfoBo.setFieldName(modelItem.getFieldName());
        fieldInfoBo.setModelFieldName(FormatStringUtil.formatPrefix(prefix, modelItem.getFieldKey()));
        fieldInfoBo.setModelFieldZhName(FormatStringUtil.formatPrefix(zhPrefix, modelItem.getFieldName()));
        fieldInfoBo.setFieldValueType(modelItem.getFieldValueType());
        fieldInfoBo.setFieldType(modelItem.getFieldType());
        fieldInfoBo.setBasicFieldType(modelItem.getFieldType());
        return fieldInfoBo;
    }

    /**
     * 根据业务模型获取所有字段明细
     * @param modelKey
     * @return
     */
    private List<ModelItem> getModelItemListByModelKey(String modelKey) {
        QueryWrapper<ModelItem> wrapper = new QueryWrapper<>();
        wrapper.eq(ModelItem.COLUMN.MODEL_KEY, modelKey);
        wrapper.isNull(ModelItem.COLUMN.IS_DELETED);
        wrapper.eq(ModelItem.COLUMN.IS_ENABLE, (short) 0);
        List<ModelItem> list = modelItemMapper.selectList(wrapper);
        return list;
    }

    private BusinessModel getBusinessModelByModelKey(String modelKey) {
        QueryWrapper<BusinessModel> wrapper = new QueryWrapper<>();
        wrapper.eq(BusinessModel.COLUMN.MODEL_KEY, modelKey);
        wrapper.isNull(BusinessModel.COLUMN.IS_DELETED);
        wrapper.eq(BusinessModel.COLUMN.IS_ENABLE, (short) 0);
        List<BusinessModel> list = businessModelMapper.selectList(wrapper);
        if (list == null || list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    private boolean verifyDbExistById(Long id) {
        QueryWrapper<BusinessModel> wrapper = new QueryWrapper<>();
        wrapper.eq(BusinessModel.COLUMN.ID, id);
        wrapper.isNull(BusinessModel.COLUMN.IS_DELETED);
        Long count = businessModelMapper.selectCount(wrapper);
        return count == 1;
    }

    /**
     * 校验数据库幂等性
     *
     * @param modelKey
     * @return
     */
    private boolean verifyDbUnique(String modelKey) {
        QueryWrapper<BusinessModel> wrapper = new QueryWrapper<>();
        wrapper.eq(BusinessModel.COLUMN.MODEL_KEY, modelKey);
        wrapper.isNull(BusinessModel.COLUMN.IS_DELETED);
        Long count = businessModelMapper.selectCount(wrapper);
        return count == 0;
    }
}
